iT邦幫忙

2023 iThome 鐵人賽

DAY 10
0
自我挑戰組

Concurrency in go 讀書心得系列 第 10

10.Confinement pattern

  • 分享至 

  • xImage
  •  

Confinement pattern

這種模式的主要目的是確保資料只在一個 goroutine 中被訪問,從而避免了競爭條件和其他並發相關的問題。

封閉模式大致可以分為兩種:不可公開封閉和可公開封閉。

不可公開封閉(Ad hoc confinement):

這是一種隱式的封閉方式,因為它完全依賴於開發人員的紀律。
在這種模式下,開發人員簡單地確保某一資料結構只在一個 goroutine 中被訪問,並且不會被共享或傳遞到其他 goroutines。
這種方式的缺點是,由於它完全依賴於開發者的紀律,所以可能容易出錯。

func main() {
	data := make([]int, 4)

	loopData := func(handleData chan<- int) {
		defer close(handleData)
		for i := range data {
			handleData <- data[i]
		}
	}

	handleData := make(chan int)
	go loopData(handleData)

	for num := range handleData {
		fmt.Println(num)
	}
}

這個範例程式碼僅僅是通過確保 data 切片的使用方式(即哪些操作是在哪個 goroutine 中執行的)來達到Ad hoc confinement,而不是通過語言特性(例如,通過某種封閉模式)來確保這一點。


可公開封閉(Lexical confinement):

這是一種明確的封閉方式,因為它依賴於語言的語法和結構。
一個典型的例子是使用 channels 來傳遞資料。當你從一個 goroutine 將資料傳遞到另一個 goroutine 時,你可以使用 channels,這樣可以確保資料的所有權只存在於一個 goroutine。
例如,如果你在一個 goroutine 中寫入資料到一個 channel,並在另一個 goroutine 中從該 channel 讀取資料,那麼你可以確保該資料在任何時候都只由一個 goroutine 訪問。

func main() {
	chanOwner := func() <-chan int {
		results := make(chan int, 5) // <1>
		go func() {
			defer close(results)
			for i := 0; i <= 5; i++ {
				results <- i
			}
		}()
		return results
	}

	consumer := func(results <-chan int) { // <3>
		for result := range results {
			fmt.Printf("Received: %d\n", result)
		}
		fmt.Println("Done receiving!")
	}

	results := chanOwner() // <2>
	consumer(results)
}

這段程式碼使用 lexical confinement 的方法,確保只有 channel 的建立者可以寫入到該 channel,而其他部分,如消費者,只能讀取。這是一個非常常見的模式,因為它提供了一個明確的方式來確保資料的一致性和安全性,避免在多個 goroutines 之間產生競爭條件。


上一篇
9.Select, GOMAXPROC
下一篇
11.For-Select-Loop
系列文
Concurrency in go 讀書心得30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言